package util;

import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;

import bean.UserType;

public class Util {
//	private static Pattern phoneNumberPattern = Pattern.compile("^([0-9\\(\\)\\/\\+ \\-]*)$");
	private static Pattern phoneNumberPattern = Pattern.compile("^(1-?)?(([2-9]\\d{2})|[2-9]\\d{2})(-|\\s)?[2-9]\\d{2}(-|\\s)?\\d{4}$");
	private static Pattern validMoneyPattern = Pattern.compile("^\\d{1,6}+(\\.\\d{1,2})?$");
	private static Pattern validBalPattern = Pattern.compile("^\\d{1,17}+(\\.\\d{1,2})?$");
	private static Pattern validFundPattern = Pattern.compile("^\\d{1,6}+(\\.\\d{1,3})?$");

	private static Pattern userNamePattern = Pattern.compile("^[a-zA-Z0-9_-]{2,15}$");
	private static Pattern tickerPattern = Pattern.compile("^[a-zA-Z]{1,5}$");
	private static Pattern cityPattern = Pattern.compile("^[a-zA-Z]{2,15}$");
	private static Pattern addressPattern = Pattern.compile("^[^%@$*]{1,20}$");
	
	private static SimpleDateFormat dbDateFormat = new SimpleDateFormat("yyyy-MM-dd");
	private static Pattern zipPattern = Pattern.compile("\\b[0-9]{5}\\b");
	
	private static DecimalFormat dfMoney = new DecimalFormat("###,###,###,###,###.00");
	private static DecimalFormat dfShare = new DecimalFormat("###,###,###,###,###.000");
	//public static Date nullDate = Date.UTC(1, 1, 1, 0, 0, 0);
	public static String getDefaultPage(UserType type,HttpServletRequest request)
	{
		String webapp = request.getContextPath();
		if(type.equals(UserType.Customer))
		{
			return webapp + "/transactionHistory.do";
		}
		else
		{
			return webapp + "/employeeConsole.jsp";
		}
	}
	
	private static SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
	
	public static String formatDate(Date date)
	{
		return dateFormat.format(date);
	}
	
	public static String showMoney(long moneyAmount)
	{
		
		double amount = (double)moneyAmount/100.00;
		return showMoney(amount);
	}
	
	public static String showMoney(double money)
	{
		return dfMoney.format(money);
	}
	
	public static String showShares(long shares)
	{
		double shareNumbers = (double)shares/1000.0;
		return dfShare.format(shareNumbers);
	}
	
	public static String showValue(long shares,long price)
	{
		double value = (double)shares*price/100000.0;
		return dfMoney.format(value);
	}
	
	public static boolean isValidTicker(String string)
	{
		Matcher matcher = tickerPattern.matcher(string);
		return matcher.matches();
	}
	
	public static boolean isValidCity(String string)
	{
		Matcher matcher = cityPattern.matcher(string);
		return matcher.matches();
	}
	
	public static boolean isValidPhoneNumber(String string)
	{
		Matcher matcher = phoneNumberPattern.matcher(string);
		return matcher.find();
	}
	
	public static boolean isValidMoneyAmount(String string)
	{
		Matcher matcher = validMoneyPattern.matcher(string);
		return matcher.find();
	}
	public static boolean isValidBalAmount(String string)
	{
		Matcher matcher = validBalPattern.matcher(string);
		return matcher.find();
	}
	public static boolean isValidFundAmount(String string)
	{
		Matcher matcher = validFundPattern.matcher(string);
		return matcher.find();
	}

	public static boolean isValidZip(String zip)
	{
		return zipPattern.matcher(zip).matches();
	}
	
	public static boolean isValidUsername(String name)
	{
		return userNamePattern.matcher(name).matches();
	}
	
	public static boolean isValidAddress(String name)
	{
		return addressPattern.matcher(name).matches();
	}
	
	public static long convertToDBMoney(String strMoney)
	{
		long l = 0;
		double d  = Double.parseDouble(strMoney);
		l = (long)(d * 100);
		return l;
	}
	
	public static String convertfromDBMoney(long lngMoney)
	{
		double d = (lngMoney / 100);
		return (""+d);
	}
	
	public static Date convertToDate(String date)
	{
		try {
			return dbDateFormat.parse(date);
		} catch (ParseException e) {
			return null;
		}
	}

	public static void checkInjection(String field, String value, List<String> errors) {
		if (value.matches(".*[<>\"].*")) errors.add(field + " may not contain angle brackets or quotes");
	}
	
	public static void checkNullAndLength(String field, String value, int maxLen, ArrayList<String> errors) {
		if (value == null || value.length() == 0) {
			errors.add(field + " is required");
		} else if (value.length() > maxLen){
			errors.add(field + " should have no more than " + maxLen + " characters.");
		}
	}
	
	  /**
	   * Add two long integers, checking for overflow.
	   * 
	   * @param a an addend
	   * @param b an addend
	   * @return the sum <code>a+b</code>
	   * @throws ArithmeticException if the result can not be represented as an
	   *         long
	   * @since 1.2
	   */
	  public static long addAndCheck(long a, long b) {
	      return addAndCheck(a, b, "overflow: add");
	  }
	  
	  /**
	   * Add two long integers, checking for overflow.
	   * 
	   * @param a an addend
	   * @param b an addend
	   * @param msg the message to use for any thrown exception.
	   * @return the sum <code>a+b</code>
	   * @throws ArithmeticException if the result can not be represented as an
	   *         long
	   * @since 1.2
	   */
	  private static long addAndCheck(long a, long b, String msg) {
	      long ret;
	      if (a > b) {
	          // use symmetry to reduce boundry cases
	          ret = addAndCheck(b, a, msg);
	      } else {
	          // assert a <= b
	          
	          if (a < 0) {
	              if (b < 0) {
	                  // check for negative overflow
	                  if (Long.MIN_VALUE - b <= a) {
	                      ret = a + b;
	                  } else {
	                      throw new ArithmeticException(msg);
	                  }
	              } else {
	                  // oppisite sign addition is always safe
	                  ret = a + b;
	              }
	          } else {
	              // assert a >= 0
	              // assert b >= 0

	              // check for positive overflow
	              if (a <= Long.MAX_VALUE - b) {
	                  ret = a + b;
	              } else {
	                  throw new ArithmeticException(msg);
	              }
	          }
	      }
	      return ret;
	  }
}
